package com.example.basic.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.basic.dao.UserMapper;
import com.example.basic.domain.Category;
import com.example.basic.domain.Event;
import com.example.basic.domain.User;
import com.example.basic.listener.CommonReadListener;
import com.example.basic.service.UserService;
import com.example.basic.util.CommonExecutor;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author mjw
 * @date 2022/8/25
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ResourceLoader resourceLoader;

    @Override
    public User findByNameAndAge(String name, Integer age) {
        return userMapper.findByNameAndAge(name, age);
    }

    @Override
    public PageInfo<User> selectAll(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<User> userList = userMapper.selectAll();
        return new PageInfo<>(userList);
    }

    @Override
    public List<User> selectBySex(String sex) {
        return userMapper.selectBySex(sex);
    }

    @Override
    public User selectById(Integer id) {
        return userMapper.selectById(id);
    }

    @Override
    public Integer addUser(User user) {
        return userMapper.addUser(user);
    }

    @Override
    public Integer addBatch(List<User> userList) {
        return userMapper.addBatch(userList);
    }

    @Override
    public Integer update(User user) {
        return userMapper.update(user);
    }

    @Override
    public Integer deleteById(Integer id) {
        return userMapper.deleteById(id);
    }

    @Override
    public Integer deleteBatch(List<Integer> idList) {
        return userMapper.deleteBatch(idList);
    }

    @Override
    public List<User> findByIds(List<Integer> ids) {
        return userMapper.findByIds(ids);
    }

    @Override
    public List<User> findByNames(List<String> names) {
        return userMapper.findByNames(names);
    }

    @Override
    public String batchImport(MultipartFile file) {
        // 将excel数据存至导入表
        String batchId = excelImport(file);
        return batchId;
    }

    public String excelImport(MultipartFile file) {
        ExcelReader excelReader = null;
        String batchId = String.valueOf(UUID.randomUUID());
        try {
            excelReader = EasyExcel.read(file.getInputStream()).headRowNumber(1).build();
            CommonReadListener<T> commonReadListener = new CommonReadListener<>(dataList -> importToData(batchId, dataList));
            ReadSheet readSheet1 = EasyExcel.readSheet(0)
                    .head(User.class)
                    .registerReadListener(commonReadListener).build();
            excelReader.read(readSheet1);
            return batchId;
        } catch (IOException e) {
            throw new RuntimeException("Import IOException");
        } finally {
            if (excelReader != null) {
                // 这里千万别忘记关闭，读的时候会创建临时文件，到时磁盘会崩的
                excelReader.finish();
            }
        }
    }

    public void importToData(String batchId, List<T> dtoList) {

        List<JSONObject> list = new ArrayList<>();
        for (int i = 0; i < dtoList.size(); i++) {
            String jsonString = JSON.toJSONString(dtoList.get(i));
            JSONObject object = JSONObject.parseObject(jsonString);
            list.add(object);
        }
        list.removeIf(JSONObject::isEmpty);
        for (int i = 0; i < list.size(); i++) {
            User user = JSONObject.toJavaObject(list.get(i), User.class);
            log.info("user[" + i + "]--->" + user);
            userMapper.addUser(user);
        }
    }

    @Override
    public void addCycle() {
        for (int i = 30000; i < 40000; i++) {
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            User user = new User(i, uuid, null, null, null);
            userMapper.addUser(user);
        }
    }


    @Override
    public List<User> selectByThread() {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        // 保存当前线程的引用
        Thread currentThread = Thread.currentThread();
        // 输出当前线程的名称和ID
        System.out.println("Current Thread Name: " + currentThread.getName());
        System.out.println("Current Thread ID: " + currentThread.getId());
        CompletableFuture<List<User>> future = CompletableFuture.supplyAsync(() -> {
            // 输出异步任务线程的名称和ID
            Thread asyncThread = Thread.currentThread();
            System.out.println("Async Thread Name: " + asyncThread.getName());
            System.out.println("Async Thread ID: " + asyncThread.getId());
            // 执行查询操作，返回结果集
            return userMapper.selectAll();
        }, executor);
        // 等待异步任务完成，并获取查询结果
        List<User> results;
        try {
            results = future.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("多线程查询的数量--->" + results.size());
        return results;
    }

    @Override
    public List<User> selectNoThread() {
        List<User> userList = userMapper.selectAll();
        System.out.println("单线程查询的数量--->" + userList.size());
        return userList;
    }

    @Override
    public List<User> selectByPartition() {
        Integer count = userMapper.countAll();
        int threadCount = 10;
        int size = 5000;
        ThreadPoolExecutor executor = CommonExecutor.buildThreadFirstExecutor("executor");
        //ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        List<Callable<List<User>>> tasks = new ArrayList<>();
        for (int i = 0; i < count; i += size) {
            int offset = i;
            Callable<List<User>> task = () -> userMapper.selectByPartition(offset, size);
            tasks.add(task);
        }
        List<User> userList = new ArrayList<>();
        try {
            List<Future<List<User>>> futures = executor.invokeAll(tasks);
            for (Future<List<User>> future : futures) {
                userList.addAll(future.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
        System.out.println("多线程分批查询的数量：" + userList.size());
        return userList; // 返回所有查询结果
    }

    @Override
    public void generatePdfDoc(HttpServletResponse response) throws Exception {
//            if (1 > 0) {
//                throw new RuntimeException("123");
//            }
        //itextpdf自带的字体，预览时会出现无法显示
//        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//        Font FontNormal = new Font(bf, 10, Font.NORMAL);
//        Font FontBold = new Font(bf, 10, Font.BOLD);
        // 使用下载的ttf文件字体
//        String fontPath = "src/main/resources/font/ALBANWTS.TTF";
//        Font FontNormal = FontFactory.getFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED,10f, Font.NORMAL, BaseColor.BLACK);
//        Font FontBold = FontFactory.getFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED,10f, Font.BOLD, BaseColor.BLACK);

        Resource resource = resourceLoader.getResource("classpath:/font/ALBANWTS.TTF");
        InputStream ins = resource.getInputStream();
        BaseFont bf = BaseFont.createFont("AaShiGeMingXinPian-2.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, IOUtils.toByteArray(ins), null);
        Font FontNormal = new Font(bf, 10, Font.NORMAL);
        Font FontBold = new Font(bf, 10, Font.BOLD);

        //设置响应格式等
        response.setContentType("application/pdf");
        //设置纸张规格为A4纸
        Rectangle rect = new Rectangle(PageSize.A4);
        Document document = new Document(rect);
        String title = "测试导出pdf";
        response.setHeader("Content-disposition", "attachment; filename=".concat(String.valueOf(URLEncoder.encode(title + ".pdf", "UTF-8"))));
        OutputStream out = response.getOutputStream();
        PdfWriter.getInstance(document, out);
        document.open();
        document.newPage();
        // 添加表格,4列
        PdfPTable table = new PdfPTable(4);
        // 设置表格宽度比例
        table.setWidthPercentage(new float[]{119, 178.5f, 178.5f, 119}, new Rectangle(PageSize.A4));
        /*
        设置表格宽度比例为%100
        table.setWidthPercentage(100);
        // 设置表格的宽度
        table.setTotalWidth(500);
        // 也可以每列分别设置宽度
        table.setTotalWidth(new float[] { 160, 70, 130, 100 });
        // 锁住宽度
        table.setLockedWidth(true);
        // 设置表格上面空白宽度
        table.setSpacingBefore(10f);
        // 设置表格下面空白宽度
        table.setSpacingAfter(10f);
        // 设置表格默认为无边框
        table.getDefaultCell().setBorder(0);
        PdfContentByte cb = writer.getDirectContent();

        // 构建每个单元格
        PdfPCell cell1 = new PdfPCell(new Paragraph("Cell 1"));
        // 边框颜色
        cell1.setBorderColor(BaseColor.BLUE);
        // 设置背景颜色
        cell1.setBackgroundColor(BaseColor.ORANGE);
        // 设置跨两行
        cell1.setRowspan(2);
        // 设置距左边的距离
        cell1.setPaddingLeft(10);
        // 设置高度
        cell1.setFixedHeight(20);
        // 设置内容水平居中显示
        cell1.setHorizontalAlignment(Element.ALIGN_CENTER);
        // 设置垂直居中
        cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
        table.addCell(cell1);

        // 设置无边框
		cell3.setBorder(Rectangle.NO_BORDER);
		cell3.setHorizontalAlignment(Element.ALIGN_CENTER);
		cell3.setVerticalAlignment(Element.ALIGN_MIDDLE);
		table.addCell(cell3);

        // 在表格添加图片
		Image cellimg = Image.getInstance(IMG1);
		PdfPCell cell4 = new PdfPCell(cellimg, true);
		cell4.setBorderColor(BaseColor.RED);
		cell4.setPaddingLeft(10);
		cell4.setFixedHeight(30);
		cell4.setHorizontalAlignment(Element.ALIGN_CENTER);
		cell4.setVerticalAlignment(Element.ALIGN_MIDDLE);
		table.addCell(cell4);

		// 增加一个条形码到表格
		Barcode128 code128 = new Barcode128();
		code128.setCode("14785236987541");
		code128.setCodeType(Barcode128.CODE128);
		// 生成条形码图片
		Image code128Image = code128.createImageWithBarcode(cb, null, null);
		// 加入到表格
		PdfPCell cellcode = new PdfPCell(code128Image, true);
		cellcode.setHorizontalAlignment(Element.ALIGN_CENTER);
		cellcode.setVerticalAlignment(Element.ALIGN_MIDDLE);
		cellcode.setFixedHeight(30);
		table.addCell(cellcode);

         */


        // 第一行
        PdfPCell cell1 = new PdfPCell();
        Paragraph p1 = new Paragraph("供应商年度总评价", FontBold);
        p1.setAlignment(Element.ALIGN_CENTER);
        cell1.addElement(p1);
        Paragraph p2 = new Paragraph("（时间范围：YYYY/MM至YYYY/MM）", FontNormal);
        p2.setAlignment(Element.ALIGN_RIGHT);
        cell1.addElement(p2);
        // 设置占用列数
        cell1.setColspan(4);
        cell1.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
        table.addCell(cell1);

        // 第二行
        PdfPCell cell21 = new PdfPCell(new Paragraph("供应商名称", FontBold));
        cell21.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell21);
        PdfPCell cell22 = new PdfPCell(new Paragraph("XXXX公司", FontBold));
        cell22.setColspan(3);
        table.addCell(cell22);

        // 第三行
        PdfPCell cell31 = new PdfPCell(new Paragraph("服务过程评价", FontBold));
        cell31.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell31.setVerticalAlignment(Element.ALIGN_MIDDLE);
        PdfPCell cell32 = new PdfPCell(new Paragraph("统计品类", FontBold));
        cell32.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell32.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell32.setColspan(2);
        PdfPCell cell33 = new PdfPCell(new Paragraph("加权分值", FontBold));
        cell33.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell33.setHorizontalAlignment(Element.ALIGN_CENTER);
        // 模拟一组数据
        List<Category> categoryList = new ArrayList<>();
        Category c1 = new Category("品类A", "12");
        Category c2 = new Category("品类B", "32");
        categoryList.add(c1);
        categoryList.add(c2);
        cell31.setRowspan(categoryList.size() + 1);
        table.addCell(cell31);
        table.addCell(cell32);
        table.addCell(cell33);
        // 填充数据
        categoryList.forEach(c -> {
            PdfPCell cell3L = new PdfPCell(new Paragraph(c.getCategoryName(), FontNormal));
            cell3L.setColspan(2);
            PdfPCell cell3R = new PdfPCell(new Paragraph(c.getScore(), FontNormal));
            table.addCell(cell3L);
            table.addCell(cell3R);
        });

        // 第四行
        PdfPCell cell41 = new PdfPCell(new Paragraph("合作事件反馈情况", FontBold));
        cell41.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell41.setVerticalAlignment(Element.ALIGN_MIDDLE);
        // 模拟一组数据
        List<Event> eventList = new ArrayList<>();
        Event e1 = new Event("xx事件（品类A）", "事件描述", BigDecimal.valueOf(1));
        Event e2 = new Event("xx事件（品类A）", "事件描述", BigDecimal.valueOf(2));
        Event e3 = new Event("xx事件（品类B）", "事件描述", BigDecimal.valueOf(12));
        Event e4 = new Event("xx事件（品类C）", "事件描述", BigDecimal.valueOf(3));
        eventList.add(e1);
        eventList.add(e2);
        eventList.add(e3);
        eventList.add(e4);
        //处理数据
        Map<String, List<Event>> eventMap = eventList.stream().peek(
                item -> item.setEventDesc("描述->" + item.getEventDesc())
        ).collect(Collectors.groupingBy(Event::getEventName));
        List<List<Event>> resultList = eventMap.values().stream().peek(value -> {
            //如果合作事件反馈情况有两行及以上，添加一行合计
            if (value.size() > 1) {
                BigDecimal scoreSum = value.stream().map(Event::getScore).reduce(BigDecimal.ZERO, BigDecimal::add);
                Event dto = new Event();
                dto.setEventName("合计（" + value.get(0).getEventName() + "）");
                dto.setScore(scoreSum);
                value.add(dto);
            }
        }).collect(Collectors.toList());
        // 统计resultList总个数
        AtomicInteger count = new AtomicInteger();
        resultList.forEach(events -> {
            count.addAndGet(events.size());
        });
        cell41.setRowspan(count.addAndGet(1));
        PdfPCell cell42 = new PdfPCell(new Paragraph("事件", FontBold));
        cell42.setHorizontalAlignment(Element.ALIGN_CENTER);
        PdfPCell cell43 = new PdfPCell(new Paragraph("事件描述", FontBold));
        cell43.setHorizontalAlignment(Element.ALIGN_CENTER);
        PdfPCell cell44 = new PdfPCell(new Paragraph("加减分值", FontBold));
        cell44.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell41);
        table.addCell(cell42);
        table.addCell(cell43);
        table.addCell(cell44);
        resultList.forEach(events -> events.forEach(e -> {
            // 填充数据
            PdfPCell cell4L = new PdfPCell(new Paragraph(e.getEventName(), FontNormal));
            PdfPCell cell4M = new PdfPCell(new Paragraph(e.getEventDesc(), FontNormal));
            PdfPCell cell4R = new PdfPCell(new Paragraph(String.valueOf(e.getScore()), FontNormal));
            table.addCell(cell4L);
            table.addCell(cell4M);
            table.addCell(cell4R);
        }));

        //第五行
        PdfPCell cell51 = new PdfPCell(new Paragraph("总计", FontBold));
        cell51.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell51.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell51.setRowspan(categoryList.size());
        table.addCell(cell51);
        // 填充数据
        categoryList.forEach(c -> {
            PdfPCell cell5L = new PdfPCell(new Paragraph(c.getCategoryName(), FontNormal));
            cell5L.setColspan(2);
            PdfPCell cell5R = new PdfPCell(new Paragraph(c.getScore(), FontNormal));
            table.addCell(cell5L);
            table.addCell(cell5R);
        });

        document.add(table);
        // 关闭文档
        document.close();
    }
}
